package common

import (
	"errors"
	"fmt"
	"reflect"
	"strconv"
	"strings"

	"github.com/google/go-cmp/cmp"
)

// SliceUnique 切片去重
func SliceUnique(input []string) []string {
	count := len(input)
	if count <= 1 {
		return input
	}
	output := make([]string, 0, count)
	tempMap := map[string]struct{}{}
	for _, v := range input {
		v = strings.Trim(v, " ")
		if v == "" {
			continue
		}
		if _, ok := tempMap[v]; !ok {
			tempMap[v] = struct{}{}
			output = append(output, v)
		}
	}
	return output
}

// InArray 判断切片中是否存在某个值(仅限少量数据时使用)
func InArray(need string, needArr []string) bool {
	for _, v := range needArr {
		if need == v {
			return true
		}
	}
	return false
}

// RemoveRepByMap 去除两个切片重复的
func RemoveRepByMap(s1 []string, s2 []string) (result []string) {
	// 将s2转为map
	result = make([]string, 0)
	tempMap := make(map[string]struct{}, len(s2))
	for _, v := range s2 {
		tempMap[v] = struct{}{}
	}
	for _, v := range s1 {
		if _, ok := tempMap[v]; !ok {
			result = append(result, v)
		}
	}
	return
}

// SliceToMap Slice转Map
func SliceToMap(s1 []string) (result map[string]struct{}) {
	result = make(map[string]struct{})
	for _, v := range s1 {
		if _, ok := result[v]; !ok {
			result[v] = struct{}{}
		}
	}
	return
}

// SliceIntUnique 切片去重
func SliceIntUnique(input []int) []int {
	count := len(input)
	if count <= 1 {
		return input
	}
	output := make([]int, 0, count)
	tempMap := map[int]struct{}{}
	for _, v := range input {
		if _, ok := tempMap[v]; !ok {
			tempMap[v] = struct{}{}
			output = append(output, v)
		}
	}
	return output
}

// GetRepeat 获取两个切片重复
func GetRepeat(s1 []int, s2 []int) (result []int) {
	// 将s2转为map
	result = make([]int, 0)
	tempMap := make(map[int]int, 0)
	for _, v := range s2 {
		tempMap[v] = 1
	}
	for _, v := range s1 {
		if _, ok := tempMap[v]; ok {
			result = append(result, v)
		}
	}
	return
}

// SliceStrToInter ...
func SliceStrToInter(s1 []string) []interface{} {
	result := make([]interface{}, 0, len(s1))
	for _, v := range s1 {
		result = append(result, v)
	}
	return result
}

// SliceIntToInter ...
func SliceIntToInter(s1 []int) []interface{} {
	result := make([]interface{}, 0, len(s1))
	for _, v := range s1 {
		result = append(result, v)
	}
	return result
}

// MinInt64 最小整数
func MinInt64(s []int64) int64 {
	var min int64
	for _, val := range s {
		if min == 0 || val <= min {
			min = val
		}
	}
	return min
}

// MinInt 最小整数
func MinInt(s []int) int {
	var min int
	for _, val := range s {
		if min == 0 || val <= min {
			min = val
		}
	}
	return min
}

// MaxInt64 最大整数
func MaxInt64(s []int64) int64 {
	var max int64
	for _, val := range s {
		if val > max {
			max = val
		}
	}
	return max
}

// MaxInt 最大整数
func MaxInt(s []int) int {
	var max int
	for _, val := range s {
		if val > max {
			max = val
		}
	}
	return max
}

// RemoveRepeatInt 去除两个切片重复的
func RemoveRepeatInt(s1 []int, s2 []int) (result []int) {
	// 将s2转为map
	result = make([]int, 0)
	tempMap := make(map[int]struct{}, len(s2))
	for _, v := range s2 {
		tempMap[v] = struct{}{}
	}
	for _, v := range s1 {
		if _, ok := tempMap[v]; !ok {
			result = append(result, v)
		}
	}
	return
}

// SliceIntToString int转string
func SliceIntToString(s1 []int) []string {
	result := make([]string, 0, len(s1))
	for _, v := range s1 {
		result = append(result, strconv.Itoa(v))
	}
	return result
}

// SliceStringToInt string转int
func SliceStringToInt(s1 []string) []int {
	result := make([]int, 0, len(s1))
	for _, v := range s1 {
		if strings.TrimSpace(v) != "" {
			result = append(result, StringToInt(strings.TrimSpace(v)))
		}
	}
	return result
}

// SliceStringToInt64 string转int64
func SliceStringToInt64(s1 []string) []int64 {
	result := make([]int64, 0, len(s1))
	for _, v := range s1 {
		if strings.TrimSpace(v) != "" {
			result = append(result, StringToInt64(strings.TrimSpace(v)))
		}
	}
	return result
}

// SliceUniqueTrim 切片去重且去除空字符串
func SliceUniqueTrim(input []string) []string {
	count := len(input)
	output := make([]string, 0, count)
	tempMap := map[string]struct{}{}
	for _, v := range input {
		v = strings.TrimSpace(v)
		if v == "" {
			continue
		}
		if _, ok := tempMap[v]; !ok {
			tempMap[v] = struct{}{}
			output = append(output, v)
		}
	}
	return output
}

func InterfaceIsNil(val interface{}) (flag bool) {
	if !reflect.ValueOf(val).IsValid() {
		return true
	}
	if IsReferenceType(reflect.ValueOf(val)) && reflect.ValueOf(val).IsNil() {
		return true
	}
	return
}

func Difference(slice1, slice2 []interface{}) []interface{} {
	switch {
	case InterfaceIsNil(slice1) && !InterfaceIsNil(slice2):
		return slice2
	case !InterfaceIsNil(slice1) && InterfaceIsNil(slice2):
		return slice1
	case InterfaceIsNil(slice1) && InterfaceIsNil(slice2):
		return []interface{}{}
	}
	if !IsArray(slice1) || !IsArray(slice2) {
		return []interface{}{}
	}
	m1V := reflect.Indirect(reflect.ValueOf(slice1))
	m2V := reflect.Indirect(reflect.ValueOf(slice2))
	if m1V.Type().Elem() != m2V.Type().Elem() {
		return []interface{}{}
	}
	m := map[interface{}]int{}
	n := reflect.MakeSlice(m1V.Type(), 0, len(slice1))
	inter := Intersect(slice1, slice2)
	for _, v := range inter {
		m[v]++
	}
	for _, value := range slice1 {
		if m[value] == 0 {
			n = reflect.Append(n, reflect.ValueOf(value))
		}
	}
	for _, v := range slice2 {
		if m[v] == 0 {
			n = reflect.Append(n, reflect.ValueOf(v))
		}
	}
	results := make([]interface{}, 0, n.Len())
	for i := 0; i < n.Len(); i++ {
		results = append(results, n.Index(i).Interface())
	}
	return results
}

func Intersect(slice1 []interface{}, slice2 []interface{}) []interface{} {
	switch {
	case InterfaceIsNil(slice1) && !InterfaceIsNil(slice2):
		return slice2
	case !InterfaceIsNil(slice1) && InterfaceIsNil(slice2):
		return slice1
	case InterfaceIsNil(slice1) && InterfaceIsNil(slice2):
		return []interface{}{}
	}
	if !IsArray(slice1) || !IsArray(slice2) {
		return []interface{}{}
	}
	m1V := reflect.Indirect(reflect.ValueOf(slice1))
	m2V := reflect.Indirect(reflect.ValueOf(slice2))
	if m1V.Type().Elem() != m2V.Type().Elem() {
		return []interface{}{}
	}
	m := map[interface{}]int{}
	n := reflect.MakeSlice(m1V.Type(), 0, len(slice1))
	for _, v := range slice1 {
		m[v]++
	}
	for _, v := range slice2 {
		times, _ := m[v]
		if times >= 1 {
			n = reflect.Append(n, reflect.ValueOf(v))
		}
	}
	results := make([]interface{}, 0, n.Len())
	for i := 0; i < n.Len(); i++ {
		results = append(results, n.Index(i).Interface())
	}
	return results
}

func IsArray(obj interface{}) bool {
	objV := reflect.ValueOf(obj)
	if !objV.IsValid() || (IsReferenceType(objV) && objV.IsNil()) {
		return false
	}
	objV = reflect.Indirect(objV)
	if !(objV.Kind() == reflect.Array || objV.Kind() == reflect.Slice) {
		return false
	}
	return true
}

func IsReferenceType(value reflect.Value) bool {
	switch value.Kind() {
	case reflect.Ptr, reflect.Chan, reflect.Interface, reflect.Func, reflect.Map, reflect.Slice:
		return true
	default:
		return false
	}
}

func ConvertArrayType(iarray interface{}) []interface{} {
	if !IsArray(iarray) {
		return []interface{}{}
	}
	objV := reflect.Indirect(reflect.ValueOf(iarray))
	result := make([]interface{}, 0, objV.Len())
	for i := 0; i < objV.Len(); i++ {
		result = append(result, objV.Index(i).Interface())
	}
	return result
}

func SplitArray(arraySize int, array []interface{}) [][]interface{} {
	result := [][]interface{}{}
	if array == nil || len(array) == 0 {
		return result
	}
	switch {
	case len(array) <= arraySize:
		return [][]interface{}{array}
	default:
		for len(array) > arraySize {
			temp := array[:arraySize]
			result = append(result, temp)
			array = array[arraySize:]
		}
		return append(result, array)
	}
}

func MergeArray(array1, array2 interface{}) (interface{}, error) {
	switch {
	case InterfaceIsNil(array1) && !InterfaceIsNil(array2):
		return array2, nil
	case InterfaceIsNil(array2) && !InterfaceIsNil(array1):
		return array1, nil
	case InterfaceIsNil(array1) && InterfaceIsNil(array2):
		return nil, errors.New("nil array is not allowed")
	}
	if !IsArray(array1) || !IsArray(array2) {
		return nil, errors.New("type of obj must be array")
	}
	array1V := reflect.Indirect(reflect.ValueOf(array1))
	array2V := reflect.Indirect(reflect.ValueOf(array2))
	if array1V.Type().Elem() != array2V.Type().Elem() {
		return nil, errors.New("the type of array1 must be the same as array2's")
	}
	return reflect.AppendSlice(array1V, array2V).Interface(), nil
}

func fanzhuang(list []interface{}) (list1 []interface{}) {
	i := 0
	j := len(list) - 1
	list1 = make([]interface{}, 0)
	for i < j {
		list1[i], list1[j] = list[j], list[i]
		i = i + 1
		j = j - 1
	}
	return
}

func IsMustElementInArray(tarElement interface{}, array interface{}) bool {
	tarElement_v := reflect.ValueOf(tarElement)
	array_v := reflect.Indirect(reflect.ValueOf(array))
	if !tarElement_v.IsValid() || !array_v.IsValid() {
		fmt.Printf("null value is no valid")
		return false
	}
	if array_v.Kind() != reflect.Array && array_v.Kind() != reflect.Slice {
		fmt.Printf("argument array is not array")
		return false
	}
	if (IsReferenceType(array_v) && array_v.IsNil()) || (IsReferenceType(tarElement_v) && tarElement_v.IsNil()) {
		fmt.Printf("null value is not allowed")
		return false
	}
	for i := 0; i < array_v.Len(); i++ {
		if cmp.Equal(tarElement, array_v.Index(i).Interface()) {
			return true
		}
	}
	return false
}
